package com.doudou.zuul.config;

import com.alibaba.fastjson.JSONObject;
import com.doudou.zuul.utils.ZuulFilterResponseUtils;
import com.netflix.client.ClientException;
import org.apache.http.conn.HttpHostConnectException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.util.HashMap;

@Component
public class ZuulFallBack implements FallbackProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZuulFallBack.class);

    @Autowired
    private AppConfig appConfig;

    public static final String READ_TIME_OUT = "读数据超时！";

    public static final String CONNECT_TIME_OUT = "连接超时！";

    public static final String NO_SERVICE_AVAILABLE = "无可用服务！";

    public static final String INNER_ERROR = "内部服务出错！";

    private ByteArrayInputStream getResponseJsonStringAndConvertStream(
            long code,
            String message,
            String error,
            boolean enableLocalLogPrefix
    ) {

        message = ZuulFilterResponseUtils.viewTipsMessage(
                enableLocalLogPrefix,
                appConfig.getLocalAppName(),
                message
        );
        JSONObject jsonParam = new JSONObject();
        //提示必须传的参数没有传递
        jsonParam.put("code", code);
        jsonParam.put("message", message);
        jsonParam.put("error", error);
        jsonParam.put("data", new HashMap<>());
        return new ByteArrayInputStream(jsonParam.toJSONString().getBytes());
    }

    @Override
    public String getRoute() {
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {

        LOGGER.info("=====================================================");
        LOGGER.info("Zuul hystrix fall back {}", cause.getMessage(), cause);
        LOGGER.info("=====================================================");

        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                //如果404 怎么办了？
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {

                //具体情况要小心求证
                Throwable causeAttach = cause.getCause();

                //无可用服务
                if (cause instanceof ClientException && causeAttach == null) {
                    return getResponseJsonStringAndConvertStream(
                            1000,
                            NO_SERVICE_AVAILABLE,
                            ((ClientException) cause).getErrorMessage(),
                            appConfig.isEnableLocalLogPrefix()
                    );
                }

                Throwable inner = causeAttach.getCause();
                if (inner != null) {
                    //操作超时
                    if (inner instanceof SocketTimeoutException) {
                        return getResponseJsonStringAndConvertStream(
                                1000,
                                READ_TIME_OUT,
                                inner.getMessage(),
                                appConfig.isEnableLocalLogPrefix()
                        );
                    }
                    //连接超时
                    if (inner instanceof HttpHostConnectException) {
                        return getResponseJsonStringAndConvertStream(
                                1000,
                                CONNECT_TIME_OUT,
                                inner.getMessage(),
                                appConfig.isEnableLocalLogPrefix()
                        );
                    }
                }
                //其他错误
                return getResponseJsonStringAndConvertStream(
                        1000,
                        INNER_ERROR,
                        cause.getMessage(),
                        appConfig.isEnableLocalLogPrefix()
                );
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
                headers.setContentType(mt);
                return headers;
            }
        };
    }
}